import logging
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db import transaction
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.authentication import TokenAuthentication
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from api_test.common.api_response import JsonResponse
from api_test.common.common import record_dynamic
from api_test.models import Project, ApiGroupLevelFirst, ApiVersionLevelFirst, ApiDataType
from api_test.serializers import ProjectSerializer, ProjectDeserializer, ProjectListSerializer, \
    ProjectMemberDeserializer, ApiGroupLevelFirstDeserializer, ApiVersionLevelFirstDeserializer, ApiDataTypeDeserializer
from guardian.shortcuts import get_objects_for_user, assign_perm

logger = logging.getLogger(__name__)  # 这里使用 __name__ 动态搜索定义的 logger 配置，这里有一个层次关系的知识点。


class ProjectList(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="page", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="当前页数"),
        openapi.Parameter(name="page_size", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER,
                          description="每页最多显示的项目数"),
        openapi.Parameter(name="name", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="项目名称"),
        openapi.Parameter(name="protocol", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="项目协议"),
    ])
    def get(self, request):
        """
        获取项目列表
        """
        try:
            page_size = int(request.GET.get("page_size", 1000))
            current_page = int(request.GET.get("page", 1))
        except (TypeError, ValueError):
            return JsonResponse(code="999985", msg="page and page_size must be integer!")
        name = request.GET.get("name")
        protocol = request.GET.get("protocol")
        structure = request.GET.get("structure")

        # 获取当前用户有查看项目权限的项目列表
        projects = get_objects_for_user(request.user, 'api_test.view_project')
        obi = projects.filter(status=1)
        if name:  # 查询的name
            obi = obi.filter(name__icontains=name)
        if protocol:  # 查询的name
            obi = obi.filter(protocol__icontains=protocol)
        if structure:  # 查询的name
            obi = obi.filter(structure__icontains=structure)

        obi = obi.order_by("id")  # 仅展示status=1的项目

        paginator = Paginator(obi, page_size)  # paginator对象
        page_sizes = paginator.num_pages  # 总页数
        total = paginator.count  # 总数
        try:
            obm = paginator.page(current_page)
        except PageNotAnInteger:
            obm = paginator.page(1)
        except EmptyPage:
            obm = paginator.page(paginator.num_pages)
        serialize = ProjectListSerializer(obm, many=True)
        return JsonResponse(data={"data": serialize.data,
                                  "current_page": current_page,
                                  "total": total,
                                  "page_sizes": page_sizes,
                                  }, code="999999", msg="成功")


class ProjectInfo(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="项目id"),
    ])
    def get(self, request):
        """
        获取项目详情
        """
        project_id = request.GET.get("project_id")
        if not project_id:
            return JsonResponse(code="999996", msg="参数有误！")
        if not project_id.isdecimal():
            return JsonResponse(code="999996", msg="参数有误！")
        # 查找项目是否存在
        try:
            obj = Project.objects.get(id=project_id)
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在！")
        serialize = ProjectSerializer(obj)

        if serialize.data["status"]:
            return JsonResponse(data=serialize.data, code="999999", msg="成功！")
        else:
            return JsonResponse(code="999985", msg="该项目已禁用")


class AddProject(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)  #

    def parameter_check(self, data):
        """
        验证参数
        """
        try:
            # 必传参数 name, protocol, structure
            if not data.get("name") or not data.get("protocol") or not data.get("structure"):
                return JsonResponse(code="999996", msg="参数有误！")
            if isinstance(data["protocol"], list):  # 将前端传来的list类型转为str类型
                data["protocol"] = str(data["protocol"])
            else:
                return JsonResponse(code="999996", msg="参数格式有误！")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误！")

    def add_project_member(self, project, user):
        """
        添加项目创建人员
        :param project: 项目ID
        :param user:  用户ID
        """
        member_serializer = ProjectMemberDeserializer(data={
            "permissionType": "超级管理员", "project": project,
            "user": user
        })
        project = Project.objects.get(id=project)
        user = User.objects.get(id=user)
        if member_serializer.is_valid():
            member_serializer.save(project=project, user=user)

    def add_project_group_version_datatype(self, project_id):
        data = {"project_id": project_id, "name": "default"}
        data_type = [{"project_id": project_id, "type": "string", "system": "1"}, {"project_id": project_id, "type": "int", "system": "1"}, {"project_id": project_id, "type": "boolean", "system": "1"}]
        project = Project.objects.get(id=project_id)

        count_group = ApiGroupLevelFirst.objects.filter(name=data["name"], project=data["project_id"]).count()
        if count_group == 0:
            serializer = ApiGroupLevelFirstDeserializer(data=data)
            if serializer.is_valid():
                serializer.save(project=project)

        count_version = ApiVersionLevelFirst.objects.filter(name=data["name"], project=data["project_id"]).count()
        if count_version == 0:
            serializer = ApiVersionLevelFirstDeserializer(data=data)
            if serializer.is_valid():
                serializer.save(project=project)

        for each in data_type:
            count_type = ApiDataType.objects.filter(type=each["type"], project=each["project_id"]).count()
            if count_type == 0:
                serializer = ApiDataTypeDeserializer(data=each)
                if serializer.is_valid():
                    serializer.save(project=project)

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['name', 'protocol', 'structure'],
        properties={
            'name': openapi.Schema(type=openapi.TYPE_STRING, description="项目名称"),
            'protocol': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_STRING),
                                       description="项目协议"),
            'structure': openapi.Schema(type=openapi.TYPE_STRING, description="接口协议"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="项目描述")
        },
    ))
    def post(self, request):
        """
        新增项目
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        data["user"] = request.user.pk
        if not data.get('game'):
            data['game'] = 1
        project_serializer = ProjectDeserializer(data=data)
        try:
            Project.objects.get(name=data["name"])
            return JsonResponse(code="999997", msg="存在相同名称")
        except ObjectDoesNotExist:
            with transaction.atomic():
                if project_serializer.is_valid():
                    project_serializer.save()

                    project_id = project_serializer.data.get("id")
                    # 记录动态
                    record_dynamic(project=project_id,
                                   _type="添加", operationObject="项目", user=request.user.pk,
                                   data="添加项目“%s”" % data["name"])
                    # 创建项目的用户添加为该项目的成员
                    self.add_project_member(project_id, request.user.pk)

                    self.add_project_group_version_datatype(project_id)

                    # 为创建项目的用户添加查看该项目的权限
                    obj = Project.objects.get(id=project_id)
                    assign_perm("view_project", request.user, obj)

                    return JsonResponse(data={
                        "project_id": project_id
                    }, code="999999", msg="成功")
                else:
                    return JsonResponse(code="999998", msg="失败", data={"errmsg": project_serializer.errors})


class UpdateProject(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 必传参数 name, protocol , structure
            if not data.get("project_id") or not data.get("name") or not data.get("protocol") or not data.get(
                    "structure"):
                return JsonResponse(code="999996", msg="参数有误！")
            # 校验project_id类型为int
            if not isinstance(data["project_id"], int):
                return JsonResponse(code="999996", msg="参数有误！")
            if isinstance(data["protocol"], list):  # 将前端传来的list类型转为str类型
                data["protocol"] = str(data["protocol"])
            else:
                return JsonResponse(code="999996", msg="参数格式有误！")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误！")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'name', 'protocol', 'structure'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'name': openapi.Schema(type=openapi.TYPE_STRING, description="项目名称"),
            'protocol': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_STRING),
                                       description="项目协议"),
            'structure': openapi.Schema(type=openapi.TYPE_STRING, description="接口协议"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="项目描述")
        },
    ))
    def post(self, request):
        """
        修改项目
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        # 查找项目是否存在
        try:
            obj = Project.objects.get(id=data["project_id"])
            # if not request.user.is_superuser and obj.user.is_superuser:
            #     return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在！")
        # 查找是否相同名称的项目
        count = Project.objects.filter(name=data["name"]).exclude(id=data["project_id"]).count()
        if count > 0:
            return JsonResponse(code="999997", msg="存在相同名称")
        else:
            serializer = ProjectDeserializer(data=data)
            with transaction.atomic():
                if serializer.is_valid():
                    # 修改项目
                    serializer.update(instance=obj, validated_data=data)
                    # 记录动态
                    record_dynamic(project=data["project_id"],
                                   _type="修改", operationObject="项目", user=request.user.pk,
                                   data="修改项目“%s”" % data["name"])
                    return JsonResponse(code="999999", msg="成功")
                else:
                    return JsonResponse(code="999998", msg="失败")


class DelProject(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 校验project_id类型为int
            if not data.get("ids") or not isinstance(data["ids"], list):
                return JsonResponse(code="999996", msg="参数有误！")
            for i in data["ids"]:
                if not isinstance(i, int) and not isinstance(int(i), int):  # 支持字符串格式的整数
                    return JsonResponse(code="999996", msg="参数有误！")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误！")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['ids'],
        properties={
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除待项目id列表"),
        },
    ))
    def post(self, request):
        """
        删除项目
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            for i in data["ids"]:
                try:
                    obj = Project.objects.get(id=i)
                    # if not request.user.is_superuser and obj.user.is_superuser:
                    #     return JsonResponse(code="999983", msg=str(obj) + "无操作权限！")
                except ObjectDoesNotExist:
                    return JsonResponse(code="999995", msg="项目不存在！")
            for j in data["ids"]:
                obj = Project.objects.get(id=j)
                obj.status = False  # 删除项目， 目前仅禁用
                obj.save()
                # 记录动态
                record_dynamic(project=j, _type="禁用", operationObject="项目", user=request.user.pk,
                               data="禁用项目“%s”" % obj.name)
            return JsonResponse(code="999999", msg="成功")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在！")
